use core::arch::asm;

const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93;

/*
  RISC-V 通用寄存器功能分类
a0~a7（ x10~x17 ） 调用者保存  用来传递输入参数。其中的 a0 和 a1 还用来保存返回值。
t0~t6( x5~x7,x28~x31 )  调用者保存  作为临时寄存器使用，在被调函数中可以随意使用无需保存。
s0~s11( x8~x9,x18~x27 )  被调用者保存  作为临时寄存器使用，被调函数保存后才能在被调函数中使用。
ra( x1 )   被调用者保存的   保存返回地址。

在 RISC-V 调用规范中，系统调用约定寄存器 a0~a6 保存系统调用的参数， a0 保存系统调用的返回值，寄存器 a7 用来传递 syscall ID。
 */
fn syscall(id: usize, args: [usize; 3]) -> isize {
    let mut ret: isize;
    unsafe {
        //内嵌汇编，执行ecall指令
        asm!(
            "ecall",
            inlateout("x10") args[0] => ret,   //指定寄存器x10用于输入和输出,将args[0]作为输入绑定到a0
            in("x11") args[1],  //编译器帮助下,将变量绑定到寄存器a1
            in("x12") args[2],  //a2
            in("x17") id  //a7
        );
    }
    ret
}

/// 功能：将内存中缓冲区中的数据写入文件。
/// 参数：`fd` 表示待写入文件的文件描述符；
///      `buf` 表示内存中缓冲区的起始地址；
///      `len` 表示内存中缓冲区的长度。
/// 返回值：返回成功写入的长度。
/// syscall ID：64
pub fn sys_write(fd: usize, buffer: &[u8]) -> isize {
    syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()])
}

/// 功能：退出应用程序并将返回值告知批处理系统。
/// 参数：`exit_code` 表示应用程序的返回值。
/// 返回值：该系统调用不应该返回。
/// syscall ID：93
pub fn sys_exit(exit_code: i32) -> isize {
    syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0])
}
